#include "CUserInterface.h"
#include "CLevelEditor.h"
#include "IGUICinematicCtrl.h"
#include "CGUICinematicCtrl.h"
#include "CProperty.h"
#include "IGUIEnvironment.h"
#include "IGUIWindow.h"
#include "IGUIComboBox.h"
#include "IGUIEditBox.h"
#include "IGUIListBox.h"
#include "IGUIButton.h"
#include "IGUICheckBox.h"
#include "IGUITabControl.h"
#include "IGUIStaticText.h"
#include "IFileSystem.h"
#include "IXMLWriter.h"
#include "IWriteFile.h"
#include "ISceneManager.h"
#include "ISceneNode.h"
#include "IrrlichtDevice.h"
#include "IReadFile.h"
#include "IWriteFile.h"
#include "CCinematicThread.h"
#include "CSceneObject.h"
#include "IGUITreeCtrl.h"
#include "IGUISpinBox.h"
#include <windows.h>
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
extern CUserInterface* ui;
extern CLevelEditor* editor;
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------

CCinematicEditor::CCinematicEditor() 
{
	m_CinematicCommands.clear();
	m_CinematicWindow = 0;
	//m_CineNameInputWindow = 0;
	m_cinematicCtrl = 0;
	m_CineFile = "";
	loadCinematicCommands();
	m_CurrentCinematicIndex = -1;
	m_PropTab = 0;
	m_SavedObjectParameters.clear();
	m_Active = false;
	m_KeyFrameList = 0;
	m_cinematicThreadSelected = 0;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
CCinematicEditor::~CCinematicEditor()
{
	for (u32 i = 0; i < m_CinematicCommands.size(); i ++)
		if (m_CinematicCommands[i])
		{
			delete m_CinematicCommands[i];
			m_CinematicCommands[i] = 0;
		}
	m_CinematicCommands.clear();

	//for (u32 i = 0; i < m_CurrentCinematic.size(); i ++)
	//	if (m_CurrentCinematic[i])
	//	{
	//		delete m_CurrentCinematic[i];
	//		m_CurrentCinematic[i] = 0;
	//	}
	//m_CurrentCinematic.clear();
	
	m_CurrentCinematic = 0;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CCinematicEditor::loadCinematicCommands()
{
	CCinematicCommand* cinematicCmd = 0;

	IXMLReader* xml = g->device->getFileSystem()->createXMLReader("cinematic_commands.xml");

	if (!xml)
		return;
	
	while (xml->read())
	{
		switch(xml->getNodeType())
		{
			case EXN_ELEMENT:
			{
				if (!wcscmp(L"command", xml->getNodeName()))
				{
					cinematicCmd = new CCinematicCommand();					
					cinematicCmd->m_id = xml->getAttributeValueAsInt(L"id");
					cinematicCmd->m_Name = xml->getAttributeValue(L"name");
					cinematicCmd->m_Attributes->read(xml, true, L"command");
					m_CinematicCommands.push_back(cinematicCmd);
					break;					
				}								
			}
			break;

			case EXN_ELEMENT_END:
				break;
		}
	}

	xml->drop();
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CCinematicEditor::createCinematicWindow()
{
	const int CINEMATIC_WINDOW_WIDTH	=	800;

	const dimension2d<u32> screen = g->driver->getScreenSize();

	stringw caption = stringw(L"Edit Cinematic ID: ") + stringw(m_Target->m_SceneNode->getID());
	rect<s32> r ((screen.Width - CINEMATIC_WINDOW_WIDTH) >> 1, 
		screen.Height - 770, ((screen.Width - CINEMATIC_WINDOW_WIDTH) >> 1) + CINEMATIC_WINDOW_WIDTH, 
		screen.Height);
	m_CinematicWindow = g->guienv->addWindow( r , false, caption.c_str(), 0, WND_ID_CINEMATIC);

	m_cinematicThreadSelected = g->guienv->addStaticText(L"Current:" , 	rect<s32>( 20, 20, 200, 35), false , false , m_CinematicWindow);

	rect<s32> r1 ( 20 , 40 , r.getWidth() - 20 , r.getHeight() / 2 - 50);
	m_cinematicCtrl = AddGUICinematicCtrl(g->guienv, r1 , m_CinematicWindow, CINEMATIC_ID_CINEMATIC_CTRL);
		
	g->guienv->setFocus(m_cinematicCtrl);
	
	rect<s32> r2 ( 20 , r.getHeight() / 2 , r.getWidth() / 2 - 20 , r.getHeight() - 70);
	m_KeyFrameList = 0;
	m_KeyFrameList = g->guienv->addListBox(r2, m_CinematicWindow, CINEMATIC_ID_KEY_FRAME_LIST, true);
	m_KeyFrameList->setSelected(-1);


	u32 ybottom = r.getHeight() - 60;
	u32 yheight = r.getHeight() - 40;
	u32 xstart = 20;
	u32 xwidth = 58;
	u32 spacing = 5;

	g->guienv->addButton(rect<s32>(xstart, ybottom ,xstart+xwidth, yheight), m_CinematicWindow, CINEMATIC_ID_UP_BTN, L"Up");
	xstart+=xwidth + spacing;
	g->guienv->addButton(rect<s32>(xstart, ybottom, xstart+xwidth, yheight), m_CinematicWindow, CINEMATIC_ID_DOWN_BTN, L"Down");
	xstart+=xwidth + spacing;
	g->guienv->addButton(rect<s32>(xstart, ybottom, xstart+xwidth, yheight), m_CinematicWindow, CINEMATIC_ID_DELETE_BTN, L"Delete");
	xstart+=xwidth + spacing;
	g->guienv->addButton(rect<s32>(xstart, ybottom, xstart+xwidth, yheight), m_CinematicWindow, CINEMATIC_ID_CLONE_BTN, L"Clone");	

	xstart+=xwidth + spacing;
	g->guienv->addButton(rect<s32>(xstart, ybottom, xstart+xwidth, yheight), m_CinematicWindow, CINEMATIC_ID_CHANGE_BTN, L"Change");

	xstart+=xwidth + spacing;
	g->guienv->addButton(rect<s32>(xstart, ybottom, xstart+xwidth, yheight), m_CinematicWindow, CINEMATIC_ID_PREVIEW_BTN, L"Preview");	

	//===================Move range cmds UI===========================
	u32 labelWidth = 35;
	u32 spinWidth = 55;
	const int k_max_column = MAX_COLUMNS;

	xstart+=xwidth + spacing + 20;
	g->guienv->addStaticText(L"start",rect<s32>(xstart, ybottom, xstart+labelWidth, yheight),false,false,m_CinematicWindow)->setTextAlignment(EGUIA_LOWERRIGHT,EGUIA_CENTER);
	xstart+=labelWidth + spacing;
	m_moveRangeStartBox = g->guienv->addSpinBox(L"",rect<s32>(xstart, ybottom, xstart+spinWidth, yheight), m_CinematicWindow);	
	m_moveRangeStartBox->setRange(0,k_max_column*EVENTS_INTERVAL);
	m_moveRangeStartBox->setValue(0);
	m_moveRangeStartBox->setDecimalPlaces(0);
	m_moveRangeStartBox->setStepSize(EVENTS_INTERVAL);	

	xstart+=spinWidth + spacing;
	g->guienv->addStaticText(L"end",rect<s32>(xstart, ybottom, xstart+labelWidth, yheight),false,false,m_CinematicWindow)->setTextAlignment(EGUIA_LOWERRIGHT,EGUIA_CENTER);;
	xstart+=labelWidth + spacing;
	m_moveRangeEndBox = g->guienv->addSpinBox(L"",rect<s32>(xstart, ybottom, xstart+spinWidth, yheight), m_CinematicWindow);	
	m_moveRangeEndBox->setRange(0,k_max_column*EVENTS_INTERVAL);
	m_moveRangeEndBox->setValue(0);
	m_moveRangeEndBox->setDecimalPlaces(0);
	m_moveRangeEndBox->setStepSize(EVENTS_INTERVAL);

	xstart+=spinWidth + spacing;
	g->guienv->addStaticText(L"offset",rect<s32>(xstart, ybottom, xstart+labelWidth, yheight),false,false,m_CinematicWindow)->setTextAlignment(EGUIA_LOWERRIGHT,EGUIA_CENTER);;
	xstart+=labelWidth + spacing;
	m_moveRangeOffsetBox = g->guienv->addSpinBox(L"",rect<s32>(xstart, ybottom, xstart+spinWidth, yheight), m_CinematicWindow);	
	m_moveRangeOffsetBox->setRange(-k_max_column,k_max_column);
	m_moveRangeOffsetBox->setValue(0);
	m_moveRangeOffsetBox->setDecimalPlaces(0);
	m_moveRangeOffsetBox->setStepSize(1);

	xstart+=spinWidth + spacing;
	g->guienv->addButton(rect<s32>(xstart, ybottom, xstart+xwidth, yheight), m_CinematicWindow, CINEMATIC_ID_MOVE_RANGE_BTN, L"Move");	

	//======================================================================	
	g->guienv->addButton(rect<s32>(720, ybottom+30, 720+xwidth, yheight+30), m_CinematicWindow, CINEMATIC_ID_SAVE_FILE, L"Save");	

	int bstart = 20;
	g->guienv->addButton(rect<s32>(bstart, ybottom+30, bstart+xwidth, yheight+30), m_CinematicWindow, CINEMATIC_ID_FIRST_KF, L"FirstKF");	
	bstart+=xwidth;
	g->guienv->addButton(rect<s32>(bstart, ybottom+30, bstart+xwidth, yheight+30), m_CinematicWindow, CINEMATIC_ID_PREVIOUS_KF, L"<<PrevKF");	
	bstart+=xwidth;
	g->guienv->addButton(rect<s32>(bstart, ybottom+30, bstart+xwidth, yheight+30), m_CinematicWindow, CINEMATIC_ID_NEXT_KF, L"NextKF>>");	
	bstart+=xwidth;
	g->guienv->addButton(rect<s32>(bstart, ybottom+30, bstart+xwidth, yheight+30), m_CinematicWindow, CINEMATIC_ID_LAST_KF, L"LastKF");	

	bstart+=xwidth+2;
	g->guienv->addButton(rect<s32>(bstart, ybottom+30, bstart+xwidth, yheight+30), m_CinematicWindow, CINEMATIC_ID_VIEW_BTN, L"View");		

	IGUIButton* b = g->guienv->addButton(rect<s32>(10 + r1.getWidth() / 2,  r.getHeight() / 2 , r1.getWidth() / 2 + 40, r.getHeight() / 2 + 25), m_CinematicWindow, CINEMATIC_ID_LINK_BTN, L"Link");		
	b->setIsPushButton(true);

	g->guienv->addButton(rect<s32>(10 + r1.getWidth() / 2,  r.getHeight() / 2 + 30, r1.getWidth() / 2 + 40, r.getHeight() / 2 + 55), m_CinematicWindow, CINEMATIC_ID_ADD_BTN, L"Add");
					
	m_CommandBox = g->guienv->addComboBox(rect<s32>( 45 +  r1.getWidth() / 2, r.getHeight() / 2 + 30 , r1.getWidth() - 60 , r.getHeight() / 2 + 55), m_CinematicWindow, CINEMATIC_ID_COMMAND_COMBO);

	g->guienv->addButton(rect<s32>(r1.getWidth()-55, r.getHeight() / 2 + 30, r1.getWidth(), r.getHeight() / 2 + 55),
							m_CinematicWindow, CINEMATIC_ID_FOCUS_BTN, L"FOCUS", L"focus the camera to the object/enemy you selected");

	
	for (u32 i = 0; i < m_CinematicCommands.size(); i ++)
		m_CommandBox->addItem(m_CinematicCommands[i]->m_Name.c_str());

	if (m_CinematicCommands.size())
		m_CommandBox->setSelected(0);

	m_ObjectsBox = g->guienv->addEditBox(L"ObjectID" , rect<s32>( 45 +  r1.getWidth() / 2, r.getHeight() / 2  , r1.getWidth() - 70  , r.getHeight() / 2 + 25) , true , m_CinematicWindow , CINEMATIC_ID_OBJECT_COMBO);
	m_ObjectsType = g->guienv->addStaticText(L"Unknown" , 	rect<s32>( r1.getWidth() - 70, r.getHeight() / 2  , r1.getWidth()   , r.getHeight() / 2 + 25) , true , false , m_CinematicWindow );
	m_CinematicWindow->bringToFront(m_cinematicCtrl);

	m_ObjectsBox->setAlignment(EGUIA_CENTER, EGUIA_CENTER, EGUIA_CENTER, EGUIA_CENTER);
	m_ObjectsType->setTextAlignment(EGUIA_CENTER , EGUIA_CENTER);
	//m_ObjectsBox = g->guienv->addComboBox(rect<s32>( 45 +  r1.getWidth() / 2, r.getHeight() / 2  , r1.getWidth() - 10  , r.getHeight() / 2 + 25), m_CinematicWindow, CINEMATIC_ID_OBJECT_COMBO);
	
	//for (u32 i = 0; i < editor->m_SceneObjects.size(); i ++)
	//{
	//	CSceneObject* obj = editor->m_SceneObjects[i];
	//	stringw name = obj->m_UserData->getAttributeAsStringW("Name") +
	//		L"(" + stringw(obj->m_SceneNode->getID()) + L")";
//
//		m_ObjectsBox->addItem( name.c_str() );
//	}

//	if (editor->m_SceneObjects.size())
//	{
//		m_ObjectsBox->setSelected(0);
//	}
	
	m_ObjectsBox->setEnabled(false);
	m_ObjectsType->setEnabled(false);
	//m_ObjectsBox->setVisible (false);

	m_CurrentCinematic = 0;
	m_CinematicThread = 0;
	
	m_oldSelectedRow = -1;
	m_oldSelectedCol = -1;
	m_oldSelectedCount = -1;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------

void CCinematicEditor::editCinematic(CSceneObject* object)
{
	if (m_Active)
	{
		g->guienv->addMessageBox(L"Error!", L"Cinematic editor already opened!");
		return;
	}

	m_Active = true;

	m_Target = object;

	SObjectParams param;
	m_SavedObjectParameters.clear();
	m_CurrentCinematicIndex = -1;

	for (u32 i = 0; i < editor->m_SceneObjects.size(); i ++)
	{
		param.pos = editor->m_SceneObjects[i]->m_SceneNode->getPosition();
		param.rot = editor->m_SceneObjects[i]->m_SceneNode->getRotation();
		param.scale = editor->m_SceneObjects[i]->m_SceneNode->getScale();
		m_SavedObjectParameters.push_back(param);
	}

	createCinematicWindow();

	m_CineFile = m_Target->m_UserData->getAttributeAsString("!ScriptFile");
	
	backupCinematic(m_CineFile,".load");
	loadCinematic(m_CineFile);
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CCinematicEditor::closeCinematic(bool bSave)
{
	if( bSave )
	{
		backupCinematic(m_CineFile,".save");
		saveCinematic(m_CineFile);
	}
	else
	{
		clearCinematic();
	}

	if (m_CinematicWindow)
	{
		m_CinematicWindow->remove();
		m_CinematicWindow = 0;
	}

	//if (m_CineNameInputWindow)
	//{
	//	m_CineNameInputWindow->remove();
	//	m_CineNameInputWindow = 0;
	//}

	m_PropTab = 0;
	m_KeyFrameList = 0;
	m_CommandBox = 0;
	//m_CineNameInputEdit = 0;

	//restore object params
	for (u32 i = 0; i < m_SavedObjectParameters.size(); i ++)
	{
		editor->m_SceneObjects[i]->m_SceneNode->setPosition(m_SavedObjectParameters[i].pos);
		core::vector3df rotate;
		m_SavedObjectParameters[i].rot.toEuler(rotate);
		editor->m_SceneObjects[i]->m_SceneNode->setRotation(rotate);
		editor->m_SceneObjects[i]->m_SceneNode->setScale(m_SavedObjectParameters[i].scale);
		editor->m_SceneObjects[i]->m_SceneNode->updateAbsolutePosition();
	}
	//ms todo 
	//delete cinematic list from 
	m_SavedObjectParameters.clear();
	
	m_Active = false;
	
	editor->setSelectedNode(0);
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
CCinematicCommand* CCinematicEditor::appendCommond(stringw cmdName, int column)
{	
	CCinematicCommand* cmdTemplate = FindCinematic(cmdName);		
	if(cmdTemplate==0)
		return 0;

	int row = m_cinematicCtrl->GetSelectedRow();

	void* data = m_cinematicCtrl->GetTableData(row, column);
	array<CCinematicCommand*> * cmds = static_cast< array<CCinematicCommand*> *>(data);

	if (cmds == 0)
	{
		cmds = new array<CCinematicCommand*>;
		m_cinematicCtrl->SetTableData(row, column, cmds);
	}

	

	CCinematicCommand* cmd = new CCinematicCommand();
	cmd->m_Name = cmdName;
	cmd->m_id = cmdTemplate->m_id;
	editor->copyAttributes(cmd->m_Attributes, cmdTemplate->m_Attributes);
	
	(*cmds).push_back(cmd);	

	m_cinematicCtrl->SetTableColor(row, column, SColor(255,0,0,0) , (L"X"));

	return cmd;	
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------

bool CCinematicEditor::receiveEvent(const SEvent& event)
{
	if (event.EventType == EET_KEY_INPUT_EVENT)
	{
		//if (event.KeyInput.Key == KEY_DELETE && !event.KeyInput.PressedDown)
		//{
		//	if (m_CurrentCinematicIndex < 0 || m_CurrentCinematicIndex > (int)m_CurrentCinematic.size() - 1)
		//		return false;

		//	if (m_CurrentCinematic[m_CurrentCinematicIndex])
		//		delete m_CurrentCinematic[m_CurrentCinematicIndex];

		//	m_CurrentCinematic[m_CurrentCinematicIndex] = 0;
		//	m_CurrentCinematic.erase(m_CurrentCinematicIndex);
		//	m_CurrentCinematicIndex = -1;
		//	createCommandProperties();
		//	updateCurrentCinematicList();

		//	return true;
		//}
		//return true;

		if(event.EventType == EET_KEY_INPUT_EVENT &&
			event.KeyInput.Key == KEY_ESCAPE)
		{
			return false;
		}
	}
	
	if (event.EventType == EET_GUI_EVENT)
	{
		if (!m_CinematicWindow)
			return false;
	}

	switch (event.GUIEvent.EventType)
	{		
		case EGET_ELEMENT_CLOSED:
			if (event.GUIEvent.Caller == m_CinematicWindow)
			{
				g->device->getGUIEnvironment()->addMessageBox(
					L"Quit" , L" Save cinematic ? " , true , EMBF_YES | EMBF_NO, 0, MSG_BOX_SAVE_CINEMATIC );
				//closeCinematic(true);
				return true;
			}

			break;

		case EGET_BUTTON_CLICKED:
			{
				switch (event.GUIEvent.Caller->getID())
				{
					case CINEMATIC_ID_UP_BTN:
						{
							if (m_CurrentCinematicIndex < 1 || !m_CurrentCinematic)
								break;
							CCinematicCommand* a = (*m_CurrentCinematic)[m_CurrentCinematicIndex - 1];
							(*m_CurrentCinematic)[m_CurrentCinematicIndex - 1] = (*m_CurrentCinematic)[m_CurrentCinematicIndex];
							(*m_CurrentCinematic)[m_CurrentCinematicIndex] = a;
							m_CurrentCinematicIndex --;
							updateCurrentCinematicList();
						}
						break;

					case CINEMATIC_ID_DOWN_BTN:
						{
							if (m_CurrentCinematicIndex < 0 || !m_CurrentCinematic || m_CurrentCinematicIndex >= (int)(*m_CurrentCinematic).size() - 1)
								break;						
							CCinematicCommand* a = (*m_CurrentCinematic)[m_CurrentCinematicIndex + 1];
							(*m_CurrentCinematic)[m_CurrentCinematicIndex + 1] = (*m_CurrentCinematic)[m_CurrentCinematicIndex];
							(*m_CurrentCinematic)[m_CurrentCinematicIndex] = a;
							m_CurrentCinematicIndex ++;
							updateCurrentCinematicList();
						}
						break;

					case CINEMATIC_ID_DELETE_BTN:
						{
							if (m_CurrentCinematicIndex < 0 ||  !m_CurrentCinematic || m_CurrentCinematicIndex > (int)(*m_CurrentCinematic).size() - 1)
								break;
							if ((*m_CurrentCinematic)[m_CurrentCinematicIndex])
								delete (*m_CurrentCinematic)[m_CurrentCinematicIndex];
							(*m_CurrentCinematic)[m_CurrentCinematicIndex] = 0;
							(*m_CurrentCinematic).erase(m_CurrentCinematicIndex);
							m_CurrentCinematicIndex = -1;

							const wchar_t* str = m_cinematicCtrl->GetSelectedText();
							
							m_cinematicCtrl->SetSelectedColor(SColor(255,0,0,0) , (*m_CurrentCinematic).size() == 0 ? (L"") : (L"X"));

							createCommandProperties();
							updateCurrentCinematicList();
						}
						break;

					case CINEMATIC_ID_CLONE_BTN:
						{
							if(m_CurrentCinematicIndex!=-1 && m_CurrentCinematic && (*m_CurrentCinematic).size() > 0)
							{
								CCinematicCommand* cmd = new CCinematicCommand();
								cmd->m_Name = (*m_CurrentCinematic)[m_CurrentCinematicIndex]->m_Name;
								cmd->m_id = (*m_CurrentCinematic)[m_CurrentCinematicIndex]->m_id;
								editor->copyAttributes(cmd->m_Attributes, (*m_CurrentCinematic)[m_CurrentCinematicIndex]->m_Attributes);								
								(*m_CurrentCinematic).push_back(cmd);							
								updateCurrentCinematicList();
								createCommandProperties();
							}						
						}
						break;

					case CINEMATIC_ID_ADD_BTN:
						{
							if(m_CurrentCinematic)
							{
								s32 idx = m_CommandBox->getSelected();
								CCinematicCommand* cmd = new CCinematicCommand();
								cmd->m_Name = m_CinematicCommands[idx]->m_Name;
								cmd->m_id = m_CinematicCommands[idx]->m_id;
								editor->copyAttributes(cmd->m_Attributes, m_CinematicCommands[idx]->m_Attributes);

								if (m_CurrentCinematicIndex > -1)
									(*m_CurrentCinematic).insert(cmd, m_CurrentCinematicIndex);
								else
								{
									m_CurrentCinematicIndex = m_KeyFrameList->getItemCount();
									(*m_CurrentCinematic).push_back(cmd);
								}

								const wchar_t* str = m_cinematicCtrl->GetSelectedText();
								m_cinematicCtrl->SetSelectedColor(SColor(255,0,0,0) , (*m_CurrentCinematic).size() == 0 ? (str) : (L"X"));

								updateCurrentCinematicList();
								createCommandProperties();

								if ( (cmd->m_Name == "ChangeCamera") && m_CinematicThread )
								{
									UpdatePropOfChangeCamera(cmd);
								}
								else if( (cmd->m_Name == "MoveObject") && m_CinematicThread && m_CinematicThread->m_Obj )
								{
									UpdatePropOfMoveObject(cmd, m_cinematicCtrl->GetSelectedColumn());
								}
								else if( (cmd->m_Name == "Transport") && m_CinematicThread && m_CinematicThread->m_Obj )
								{
									const int k_transport_black_ms = 1100;
									CCinematicCommand* cmd;

									int column = m_cinematicCtrl->GetSelectedColumn() + k_transport_black_ms/EVENTS_INTERVAL;
									
									appendCommond("SetCameraArea", column);	
									
									cmd = appendCommond("MoveObject", column);
									if(cmd!=0)
									{
										UpdatePropOfMoveObject(cmd, column);
									}
									
									cmd = appendCommond("SetAnim", column);
									if(cmd!=0)
									{
										cmd->m_Attributes->setAttribute("$Anim","idle_stand");
									}
								}
							}
						}
						break;
					case CINEMATIC_ID_FOCUS_BTN:
						{
							if(m_CurrentCinematicIndex!=-1 && m_CurrentCinematic && (*m_CurrentCinematic).size() > 0)
							{
								CCinematicCommand* cmd  = (*m_CurrentCinematic)[m_CurrentCinematicIndex];
								IAttributes* attr = cmd->m_Attributes;
								stringc name =  attr->getAttributeName(0);
								if( name == "ObjectID" || name == "IDEnemy" )
								{
									int id = attr->getAttributeAsInt(0);
									CSceneObject* object =  editor->getSceneObjectFromID(id);
									if(object)
									{
										void focusCameraOn (ISceneNode*);
										focusCameraOn(object->m_SceneNode);
									}
								}

							}
						}
						break;
					
					case CINEMATIC_ID_CHANGE_BTN:
						{
							if (m_CurrentCinematicIndex < 0 ||  !m_CurrentCinematic || m_CurrentCinematicIndex > (int)(*m_CurrentCinematic).size() - 1)
							{
								break;
							}

							if(m_CinematicThread != NULL)
							{								
								const irr::core::stringw ChangeCameraCmd = "ChangeCamera";
								const irr::core::stringw MoveObjCmd = "MoveObject";
								const irr::core::stringw PlayEffectCmd = "PlayEffect"; //set effect pos by dummy object

								CCinematicCommand* cmd = (*m_CurrentCinematic)[m_CurrentCinematicIndex];

								if (cmd!=NULL)
								{									
									if( (E_THREAD_TYPE_CAMERA == m_CinematicThread->m_Type) &&
										( cmd->m_Name == ChangeCameraCmd ) )
									{										
										int nowTime = (m_cinematicCtrl->GetSelectedColumn()-1)*EVENTS_INTERVAL;
										editor->ChangeCamera(true,false,cmd,nowTime);
									}
									else if( ( E_THREAD_TYPE_OBJ == m_CinematicThread->m_Type || E_THREAD_TYPE_PLAYER == m_CinematicThread->m_Type) &&
										( cmd->m_Name == MoveObjCmd ) )
									{
										int nowTime = (m_cinematicCtrl->GetSelectedColumn()-1)*EVENTS_INTERVAL;
										editor->MoveObject(true,m_CinematicThread->m_Obj,cmd,nowTime);
									}
									else if( (E_THREAD_TYPE_CAMERA!=m_CinematicThread->m_Type) &&
										( cmd->m_Name == PlayEffectCmd ) )
									{
										int nowTime = (m_cinematicCtrl->GetSelectedColumn()-1)*EVENTS_INTERVAL;
										int dummyObjID = cmd->m_Attributes->getAttributeAsInt("^dummy object");
										if(dummyObjID>=0)
										{
											CSceneObject* pObj = editor->getSceneObjectFromID(dummyObjID);
											editor->MoveObject(true,pObj,cmd,nowTime,true);
										}										
									}
									else if( 
										(cmd->m_Name != MoveObjCmd) && 
										(cmd->m_Name != ChangeCameraCmd) &&
										(cmd->m_Name != PlayEffectCmd)
										)
									{
										g->guienv->addMessageBox(L"Error!", L"Must be [ChangeCamera], [Move Object] or [Play Effect] command!!!", true);
										break;
									}									
								}
							}							
						}
						break;

					case CINEMATIC_ID_PREVIEW_BTN:
						{
							editor->OnOffPlayCinematic(true, false);
						}
						break;

					case CINEMATIC_ID_VIEW_BTN:
						{
							editor->OnOffPlayCinematic(true, true);
						}
						break;

					case CINEMATIC_ID_MOVE_RANGE_BTN:
						{							
							MoveRangeCmds(false);
						}
						break;

					case CINEMATIC_ID_SAVE_FILE:
						{
							backupCinematic(m_CineFile,".save");
							saveCinematic(m_CineFile,false);
						}
						break;

					case CINEMATIC_ID_FIRST_KF:
						{
							JumpToKeyFrame(KF_FIRST);
						}
						break;

					case CINEMATIC_ID_LAST_KF:
						{
							JumpToKeyFrame(KF_LAST);
						}
						break;

					case CINEMATIC_ID_PREVIOUS_KF:
						{
							JumpToKeyFrame(KF_PREV);
						}
						break;

					case CINEMATIC_ID_NEXT_KF:
						{
							JumpToKeyFrame(KF_NEXT);
						}
						break;

					case CINEMATIC_ID_FILE_BROWSE_BUTTON:
						{
							return propertyButtonPressed(event);
						}
						break;
				}
			}
			break;

		case EGET_FILE_SELECTED:
			{
				switch(event.GUIEvent.Caller->getID())
				{
					case FILE_PROP_FILE_OPEN_DIALOG:
						{
							SEvent evt;
							evt.GUIEvent.Caller = ui->m_FileOpenProp->m_GUIElementEdit;
							return propertyEditBoxEnter(evt);							
						}
						break;
				}
			}
			break;

		case EGET_LISTBOX_CHANGED:
			if (event.GUIEvent.Caller == m_KeyFrameList)
			{
				if (m_CurrentCinematicIndex == m_KeyFrameList->getSelected())
				{
					m_CurrentCinematicIndex = -1;
					m_KeyFrameList->setSelected(-1);
				}
				else
					m_CurrentCinematicIndex = m_KeyFrameList->getSelected();
				
				createCommandProperties();
				executeCinematicToSelection();
			}
			
			break;
		case EGET_COMBO_BOX_CHANGED:
			{
				IGUIComboBox* comboBox = (IGUIComboBox*)event.GUIEvent.Caller;
				
				//if (comboBox == m_ObjectsBox)
				//{
				//	//set this thread's object to this ...
				//	void * data = m_cinematicCtrl->GetSelectedData();

				//	CCinematicThread* cmd = static_cast<CCinematicThread*>(data);
				//	s32 selected = comboBox->getSelected();
				//	if (cmd && cmd->m_Type == E_THREAD_TYPE_OBJ)
				//	{																		
				//		for (u32 i = 0; i < editor->m_SceneObjects.size(); i ++)
				//		{
				//			if (i == selected)
				//			{
				//				CSceneObject* obj = editor->m_SceneObjects[i];
				//				cmd->m_Obj = obj;	
				//				break;
				//			}	
				//		}						
				//	 }
				//	
				//	break;
				//}

				CProperty* changedProp = 0;

				for (u32 i = 0; i < m_CinematicProperties.size(); i ++)	
				{
					if (m_CinematicProperties[i].m_GUIElementEdit == comboBox)
					{
						changedProp = &m_CinematicProperties[i];
						break;
					}
				}

				if (changedProp)
				{
					//comboBox only for user data for now
					if ((*m_CurrentCinematic)[m_CurrentCinematicIndex]->m_Attributes)
					{
						if (changedProp->m_Name.c_str()[0] == L'^')
						{
							int id = -1;
							if (comboBox->getSelected() != 0)
							{
								stringw filter = FindStringBetween(changedProp->m_Name, L'^', 1);	

								int nb = 0;
								CSceneObject* pObject = NULL;
								
								for (u32 i = 0; i < editor->m_SceneObjects.size(); i++)
								{
									if (filter == L"" || filter == editor->m_SceneObjects[i]->m_UserData->getAttributeAsStringW("!GameType"))
									{
										if (nb == comboBox->getSelected() - 1)
										{
											pObject = editor->m_SceneObjects[i];
											break;
										}
										nb++;
									}
								}	

								if (pObject)
								{
									(*m_CurrentCinematic)[m_CurrentCinematicIndex]->m_Attributes->setAttribute(stringc(changedProp->m_Name.c_str()).c_str(), pObject->m_SceneNode->getID());
								}
							}									
						}
						else if (changedProp->m_Name.find(L"$") != -1 )
						{
							if (changedProp->m_Name == "$Anim")
							{
								CCinematicCommand* cmd = (*m_CurrentCinematic)[m_CurrentCinematicIndex];								

								cmd->m_Attributes->setAttribute(stringc(changedProp->m_Name.c_str()).c_str() , animationList[comboBox->getSelected()].c_str() );

								//if (m_CinematicThread && m_CinematicThread->m_Obj)
								//{									
								//	s32 time = m_CinematicThread->m_Obj->GetCurrentAnimationTime(comboBox->getSelected());

								//	m_cinematicCtrl->SetSelectedColor(SColor(255,0,0,0) , (L"+") , time / EVENTS_INTERVAL );
								//}
							}
							else
							{
								int pos = changedProp->m_Name.find(L"$");
								array<stringw> listArray = editor->getGameListArray(changedProp->m_Name.subString(pos+1, changedProp->m_Name.size() - 1));

								// weird -1 operation to let me have unlock command have a unselected select
								int selected = comboBox->getSelected() - 1;
								stringc propName = changedProp->m_Name.c_str();
								const char* name = propName.c_str();

								if (changedProp->m_Type == EAT_INT )
								{
									const wchar_t* val = stringw(selected + 1).c_str();									
									(*m_CurrentCinematic)[m_CurrentCinematicIndex]->m_Attributes->setAttribute(name , val);
								}
								else if (changedProp->m_Type == EAT_STRING )
								{									
									const wchar_t* val = L"";									
									if (selected > -1)
									{									
										val = listArray[selected].c_str();	
									}									
									(*m_CurrentCinematic)[m_CurrentCinematicIndex]->m_Attributes->setAttribute(name , val);
								}								
							}
						}
					}
				}
			}
			
			updateTimeLine();

			break;
		case EGET_CHECKBOX_CHANGED:
		{		

			IGUICheckBox* editBox = (IGUICheckBox*)event.GUIEvent.Caller;

			CProperty* changedProp = 0;

			for (u32 i = 0; i < m_CinematicProperties.size(); i ++)	
				if (m_CinematicProperties[i].m_GUIElementEdit == editBox)
				{
					changedProp = &m_CinematicProperties[i];
					break;
				}
			
			if (changedProp)
			{	
				(*m_CurrentCinematic)[m_CurrentCinematicIndex]->m_Attributes->setAttribute(
					stringc(changedProp->m_Name.c_str()).c_str(), editBox->isChecked());
				return true;
			}
		}
			break;
		case EGET_TABLE_CHANGED:
		case EGET_TABLE_SELECTED_AGAIN:
		{	
			m_CinematicThread = 0;
			if (m_cinematicCtrl->GetSelectedRow() < 0) {
				break;
			}
			void* cdata = m_cinematicCtrl->GetTableData( m_cinematicCtrl->GetSelectedRow() , 0 );
			CCinematicThread* cmd = static_cast<CCinematicThread*>(cdata);		
			if (cmd == 0) {
				break;
			}
			if (cmd && cmd->m_Type == E_THREAD_TYPE_OBJ)				  
			{
				m_CinematicThread = cmd;
			}
			else if (cmd && cmd->m_Type == E_THREAD_TYPE_CAMERA)				  
			{
				m_CinematicThread = cmd;
			}
			else if (cmd && cmd->m_Type == E_THREAD_TYPE_PLAYER)				  
			{
				m_CinematicThread = cmd;
			}
			//selecting a column but not the first one ...
			int selectedColumn = m_cinematicCtrl->GetSelectedColumn();
			if (selectedColumn!= 0)
			{
				m_moveRangeStartBox->setValue((selectedColumn-1)*EVENTS_INTERVAL);
				m_moveRangeEndBox->setValue((selectedColumn-1)*EVENTS_INTERVAL);

				void* data = m_cinematicCtrl->GetSelectedData();
				array<CCinematicCommand*> * cmds = static_cast< array<CCinematicCommand*> *>(data);

				if (cmds != 0)
				{
					m_CurrentCinematic = cmds;
				}
				else
				{
					cmds = new array<CCinematicCommand*>;
					m_CurrentCinematic = cmds;
					m_cinematicCtrl->SetSelectedData((void*)cmds);					
				}

				//enable buttons 
				enableKFButtons(true);

				const wchar_t* str = m_cinematicCtrl->GetSelectedText();

				m_cinematicCtrl->SetSelectedColor(SColor(255,0,0,0) , (*m_CurrentCinematic).size() == 0 ? (str) : (L"X"));

				updateTimeLine();

				m_ObjectsBox->setEnabled(false);

				if (m_CinematicThread && m_CinematicThread->m_Obj && m_CinematicThread->m_Obj->m_SceneNode->getID() != -1)
				{											
					m_ObjectsBox->setText( stringw(m_CinematicThread->m_Obj->m_SceneNode->getID()).c_str());								
					m_ObjectsType->setText( m_CinematicThread->m_Obj->m_UserData->getAttributeAsStringW("!GameType").c_str() );				
				}
				else
				{
					m_ObjectsBox->setText( L"");
					m_ObjectsType->setText( L"");
				}
			}
			else //selecting  a column with thread information
			{			
				m_CurrentCinematic = 0;

				//disable buttons 
				enableKFButtons(false);

				if (cmd && (cmd->m_Type == E_THREAD_TYPE_OBJ || cmd->m_Type == E_THREAD_TYPE_PLAYER || cmd->m_Type == E_THREAD_TYPE_CAMERA) )				  
				{

					m_ObjectsBox->setEnabled(true);	

					if (cmd->m_Obj && cmd->m_Obj->m_SceneNode->getID() != -1)
					{											
						m_ObjectsBox->setText( stringw(cmd->m_Obj->m_SceneNode->getID()).c_str());								
						m_ObjectsType->setText( cmd->m_Obj->m_UserData->getAttributeAsStringW("!GameType").c_str() );				
					}
					else
					{
						m_ObjectsBox->setText( L"");								
						m_ObjectsType->setText( L"");	
					}
				}
				else
				{
					m_ObjectsBox->setText( L"");								
					m_ObjectsType->setText( L"");	
					m_ObjectsBox->setEnabled(false);
				}
				//go through all commands and update m_ThreadAllCinematic	

				if (cmd)
				{
					m_CurrentCinematic = cmd->m_ThreadCinematics;

					cmd->m_ThreadCinematics->clear();
						
					int columns = m_cinematicCtrl->GetTableColumns();
												
					for (u32 j = 1 ; j < columns ; j++ )
					{
						void* data = m_cinematicCtrl->GetTableData(  m_cinematicCtrl->GetSelectedRow() , j );
						array<CCinematicCommand*>* commands = static_cast<array<CCinematicCommand*>*>(data);
						if (commands && (*commands).size() > 0)
						{													
							for (u32 k = 0 ; k < (*commands).size(); k++)
							{
								CCinematicCommand* cmd = (*commands)[k];
								m_CurrentCinematic->push_back(cmd);
							}								
						}
					}
				}
			}

		
			m_CurrentCinematicIndex = 0;
			createCommandProperties();
			updateCurrentCinematicList();

			stringw str = stringw(L"Current: ") + cmd->m_Name;
			m_cinematicThreadSelected->setText(str.c_str());
			return true;			
		}
		case EGET_EDITBOX_ENTER:
		{
			IGUIEditBox * editBox = (IGUIEditBox*)event.GUIEvent.Caller;

			if ( editBox == m_ObjectsBox)
			{
				s32 objId = ui->stringToInt( editBox->getText() );

				SetThreadObject(objId);
			}
			else
			{
				return propertyEditBoxEnter(event);
			}

			break;
		}

		case EGET_MESSAGEBOX_YES:
		{
			if (event.GUIEvent.Caller->getID() == MSG_BOX_CONFIRM_MOVE_RANGE)
			{
				MoveRangeCmds(true);
				return true;
			}
			break;
		}
		
	}

	return false;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CCinematicEditor::updateWindowPosition()
{
	if (m_CinematicWindow)
	{
		const dimension2d<u32> screen = g->driver->getScreenSize();	
		//m_CinematicWindow->setPosition(rect<s32>((screen.Width - 440) >> 1, screen.Height - 200, ((screen.Width - 440) >> 1) + 440, screen.Height));
	}
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CCinematicEditor::loadCinematic(stringc fileName)
{
	CCinematicThread* thread = 0;
	CCinematicCommand* cinematicCmd = 0;
	array<CCinematicCommand*>* list = 0;

	IXMLReader* xml = g->device->getFileSystem()->createXMLReader(fileName.c_str());
	
	int currentColumn = -1;

	if (!xml)
		return;
	
	while (xml->read())
	{
		switch(xml->getNodeType())
		{
			case EXN_ELEMENT:
			{
				if (!wcscmp(L"cinematicThread", xml->getNodeName()))
				{
					thread = new CCinematicThread(xml->getAttributeValueAsInt(L"type")); 
					thread->m_Name = xml->getAttributeValueSafe(L"name");
					s32 objID = xml->getAttributeValueAsInt(L"object");
					CSceneObject* obj = editor->getSceneObjectFromID(objID);
					
					if (obj)
					{
						thread->m_Obj = obj;
					}

					if (m_cinematicCtrl)
					{
						m_cinematicCtrl->AddThread(thread);						
					}
				}
				else if (!wcscmp(L"time", xml->getNodeName()))
				{
					list = new array<CCinematicCommand*>;
					currentColumn = (xml->getAttributeValueAsInt(L"stamp") / EVENTS_INTERVAL) + 1;
				} 
				else if (!wcscmp(L"command", xml->getNodeName()))
				{
					cinematicCmd = new CCinematicCommand();
					cinematicCmd->m_id = xml->getAttributeValueAsInt(L"id");
					cinematicCmd->m_Name = xml->getAttributeValue(L"name");

					if (!cinematicCmd->m_id)
					{
						cinematicCmd->m_id = FindId(cinematicCmd->m_Name);
					}					
				}								

				if (!wcscmp(L"attributes", xml->getNodeName()))
				{
					if (cinematicCmd)
					{
						CCinematicCommand* cmd = FindCinematic(cinematicCmd->m_Name);
						assert(cmd);

						editor->copyAttributes(cinematicCmd->m_Attributes,cmd->m_Attributes );

						cinematicCmd->m_Attributes->read(xml, false);				

						//discard atributes that no longer match current command 						
					}
				}								
			}
			break;

			case EXN_ELEMENT_END:
			{
				
				if (!wcscmp(L"time", xml->getNodeName()))
				{
					//push the list in the table 
					int row = m_cinematicCtrl->GetTableRows() - 1;
					
					if (row >= 0 && currentColumn > 0)
					{
						m_cinematicCtrl->SetTableData( row  , currentColumn , (void*)list);
						m_cinematicCtrl->SetTableColor( row , currentColumn , SColor(255 , 0 ,0,0) , L"X");
						list = 0;
						currentColumn = -1;
					}
				}

				if (!wcscmp(L"command", xml->getNodeName()))
				{
					//push this command in the list 
					(*list).push_back(cinematicCmd);
					cinematicCmd = 0;
				}
				
				if (!wcscmp(L"cinematicThread", xml->getNodeName()))
				{
					thread = 0;
				}
				break;
			}
			
		}
	}

	xml->drop();

	updateCurrentCinematicList();
}

void CCinematicEditor::backupCinematic(stringc fileName, stringc backupExt)
{
	irr::io::IFileSystem* pFs = g->device->getFileSystem();
	if( !pFs->existFile(fileName ) )
	{
		return;
	}

	IReadFile* pFile = pFs->createAndOpenFile( fileName.c_str() );
	long fileSize =  pFile->getSize();
	irr::c8 *pBuffer = new irr::c8[fileSize];
	pFile->read(pBuffer,fileSize);

	irr::core::stringc fileNameBack = fileName;
	fileNameBack+=backupExt;

	IWriteFile* pFileBack = pFs->createAndWriteFile( fileNameBack.c_str() );
	pFileBack->write(pBuffer,fileSize);
	delete[] pBuffer;

	pFile->drop();
	pFileBack->drop();
}
//--------------------------------------------------------------------------------------------------
//
void CCinematicEditor::clearCinematic()
{
	if (m_cinematicCtrl)
	{
		int rows = m_cinematicCtrl->GetTableRows();
		int columns = m_cinematicCtrl->GetTableColumns();

		CCinematicThread* cmdThread = 0;

		for (u32 i = 0 ; i < rows ; i++ )
		{
			void * cdata = m_cinematicCtrl->GetTableData( i , 0 );
			cmdThread = static_cast<CCinematicThread*>(cdata);
			if (cmdThread)
			{
				s32 objId = -1;
				if (cmdThread->m_Obj)
				{
					objId = cmdThread->m_Obj->m_SceneNode->getID();
				}						
			}

			for (u32 j = 1 ; j < columns ; j++ )
			{
				void * data = m_cinematicCtrl->GetTableData( i , j );
				array<CCinematicCommand*>* commands = static_cast<array<CCinematicCommand*>*>(data);
				if (commands)
				{
					//modify by lichuan 2009/12/18
					if( (*commands).size() > 0 )
					{
						for (u32 k = 0 ; k < (*commands).size(); k++)
						{
							CCinematicCommand* cmd = (*commands)[k];
							delete cmd;
						}	
						delete commands;
						m_cinematicCtrl->SetTableData( i , j, NULL);						
					}					
				}				
			}

			if (cmdThread)
			{
				delete cmdThread;
				m_cinematicCtrl->SetTableData( i , 0, NULL);				
			}
		}
	}
}
//--------------------------------------------------------------------------------------------------
void CCinematicEditor::saveCinematic(stringc fileName, bool close)
{
	if (!fileName.size())
		return;

	IXMLWriter* xml = g->device->getFileSystem()->createXMLWriter(fileName.c_str());

	if (!xml)
		return;
	
	xml->writeXMLHeader(); 
	xml->writeLineBreak();
	
	xml->writeComment(L"Cinematic file");	
	xml->writeLineBreak();

	if (m_cinematicCtrl)
	{
		int rows = m_cinematicCtrl->GetTableRows();
		int columns = m_cinematicCtrl->GetTableColumns();

		CCinematicThread* cmdThread = 0;

		for (u32 i = 0 ; i < rows ; i++ )
		{
			void * cdata = m_cinematicCtrl->GetTableData( i , 0 );
			cmdThread = static_cast<CCinematicThread*>(cdata);
			if (cmdThread)
			{
				s32 objId = -1;
				if (cmdThread->m_Obj)
				{
					objId = cmdThread->m_Obj->m_SceneNode->getID();
				}
				xml->writeLineBreak();
				xml->writeElement(L"cinematicThread", false , 
					L"type" , stringw(cmdThread->m_Type).c_str() , 
					L"name" , cmdThread->m_Name.c_str() ,
					L"object" , stringw(objId).c_str() );
				xml->writeLineBreak();
				//all commands here 			
			}

			for (u32 j = 1 ; j < columns ; j++ )
			{
				void * data = m_cinematicCtrl->GetTableData( i , j );
				array<CCinematicCommand*>* commands = static_cast<array<CCinematicCommand*>*>(data);
				if (commands)
				{
					//modify by lichuan 2009/12/18
					if( (*commands).size() > 0 )
					{
						int timeStampValue = (j - 1) * EVENTS_INTERVAL;
						xml->writeElement(L"time", false, L"stamp", stringw( timeStampValue ).c_str() );
						xml->writeLineBreak();

						for (u32 k = 0 ; k < (*commands).size(); k++)
						{
							CCinematicCommand* cmd = (*commands)[k];
							if( cmd->m_Name == "MoveObject" )//add by lichuan 2010/02/02
							{
								if( cmdThread->m_Type == E_THREAD_TYPE_OBJ )
								{
									irr::core::matrix4 parent = cmdThread->m_Obj->m_SceneNode->getParent()->getAbsoluteTransformation();									
									irr::core::matrix4 myself;
									myself.makeIdentity();
									irr::core::vector3df pos = cmd->m_Attributes->getAttributeAsVector3d("pos");
									myself.setTranslation( pos );
									
									irr::core::matrix4 absMat;
									absMat = parent * myself;

									irr::core::vector3df abspos = cmd->m_Attributes->getAttributeAsVector3d("abspos");
									irr::core::vector3df newAbspos = absMat.getTranslation();
									if( abspos != newAbspos )
									{
										//irr::core::stringw text = irr::core::stringw(L"ThreadName: ");
										//text += cmdThread->m_Name;
										//text += irr::core::stringw( L" ,MoveObject cmd,time=");										
										//text += irr::core::stringw( timeStampValue );
										//text += irr::core::stringw( L"\n");
										//text += irr::core::stringw( L"absPos is different.Change it ! \n");

										//char buf[200];
										//memset(buf,0,sizeof(buf));
										//sprintf(buf,"oldX=%f,oldY=%f,oldZ=%f \n", abspos.X,abspos.Y ,abspos.Z );
										//text += irr::core::stringw(buf);

										//memset(buf,0,sizeof(buf));
										//sprintf(buf,"newX=%f,newY=%f,newZ=%f \n", newAbspos.X,newAbspos.Y ,newAbspos.Z );
										//text += irr::core::stringw(buf);
										//g->guienv->addMessageBox(L"warning",text.c_str(),true,EMBF_OK,this->m_CinematicWindow);

										//printf("MoveObject cmd,absPos is different.cmdTime=%d\n", timeStampValue);
										//printf("abspos X=%f,Y=%f,Z=%f.\n",abspos.X,abspos.Y,abspos.Z);
										//printf("newAbspos X=%f,Y=%f,Z=%f.\n",newAbspos.X,newAbspos.Y,newAbspos.Z);
										//cmd->m_Attributes->setAttribute("abspos",newAbspos);
									}
								}
								else if( cmdThread->m_Type == E_THREAD_TYPE_PLAYER )
								{
									irr::core::vector3df pos = cmd->m_Attributes->getAttributeAsVector3d("pos");
									irr::core::vector3df abspos = cmd->m_Attributes->getAttributeAsVector3d("abspos");
									if( abspos != pos )
									{
										cmd->m_Attributes->setAttribute("abspos",pos);
										//if(m_CurrentCinematicIndex>=0) //delete it for avoid crash
										//	updateProperties();
									}
								}
							}
							xml->writeElement(L"command", false, L"name", cmd->m_Name.c_str() , L"id" , stringw(cmd->m_id).c_str());
							xml->writeLineBreak();
							cmd->m_Attributes->write(xml, false);
							xml->writeClosingTag(L"command");
							xml->writeLineBreak();
							if(close)
							{
								delete cmd;
							}
						}	

						xml->writeClosingTag(L"time");
						xml->writeLineBreak();
						if(close)
						{
							delete commands;
							m_cinematicCtrl->SetTableData( i , j, NULL);
						}
					}
					else
					{
						printf("size of command list is 0.\n");
					}
				}				
			}

			if (cmdThread)
			{
				xml->writeClosingTag(L"cinematicThread");
				xml->writeLineBreak();
				if(close)
				{
					delete cmdThread;
					m_cinematicCtrl->SetTableData( i , 0, NULL);
				}
			}
		}
	}	
	xml->drop();
}

stringw CCinematicEditor::FindStringBetween(stringw str, wchar_t c, int beginPos)
{
	stringw filter = L"";
	int nextBeginPos = str.findNext(c, beginPos);
	if (nextBeginPos != -1)
	{
		int endPos = str.findNext(L'^', nextBeginPos + 1);
		if( endPos != -1 )
		{
			filter = str.subString(nextBeginPos + 1, endPos - nextBeginPos - 1);
		}
		else
		{
			filter = str.subString(nextBeginPos + 1, str.size() - nextBeginPos - 1);
		}
	}			

	return filter;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
int CCinematicEditor::createProperty(stringw name, int type, s32 x, s32 y, IGUIElement* parent , CCinematicCommand* cmd)
{
	int height = 0;
	int propWidth = parent->getAbsolutePosition().getWidth() - 10;
	IGUIElement* edit = 0;
	IGUIElement* button = 0;

	// for display the name of the object to notice GD
	IGUIElement* objectName = 0;

	bool fileDialog = false;
	stringw label;
	bool bReadOnly = false;

	if ((name == L"Mesh") || (name.find(L"Texture") >= 0) || (name.find(L"File") >= 0))
		fileDialog = true;

	if (fileDialog)
	{
		propWidth = 170;	//20 pixels for file dialog btn
		button = g->guienv->addButton(rect<s32>(x + 170, y + 15, x + 190, y + 35), parent, CINEMATIC_ID_FILE_BROWSE_BUTTON, L"...");
	}

	label = name;
	
	switch (type)
	{
		case EAT_INT:
			{
				g->guienv->addStaticText(name.c_str(), rect<s32>(x, y, x + 150, y + 20), 
						false, false, parent, 1);
				
				if (name.c_str()[0] == L'^')
				{				
					stringw filter = FindStringBetween(name, L'^', 1);		

					edit = g->guienv->addComboBox(rect<s32>(x + 150, y , x + propWidth, y + 20), parent, 1);

					((IGUIComboBox*)edit)->addItem(L"None");

					for (u32 z = 0; z < editor->m_SceneObjects.size(); z ++)
					{
						if (filter == L"" || filter == editor->m_SceneObjects[z]->m_UserData->getAttributeAsStringW("!GameType"))
						{
							stringw itemName = stringw(editor->m_SceneObjects[z]->m_SceneNode->getID()) +
								" - " + editor->m_SceneObjects[z]->m_UserData->getAttributeAsStringW("Name");
							((IGUIComboBox*)edit)->addItem(itemName.c_str());
						}
					}	

					height += 20;
				}
				else if (name.c_str()[0] == L'$')
				{
					edit = g->guienv->addComboBox(rect<s32>(x, y + 15, x + propWidth, y + 35), parent, 1);
					((IGUIComboBox*)edit)->addItem(L""); 

					array<stringw> listArray = editor->getGameListArray(name.subString(1, name.size() - 1));

					for (u32 z = 0; z < listArray.size(); z ++)
						((IGUIComboBox*)edit)->addItem(listArray[z].c_str());

					height += 20;

				}
				else
				{
					edit = g->guienv->addEditBox(L"", rect<s32>(x + 100, y, x + propWidth/2, y + 20), true,parent, 1);

					// set the ui for display name for Object and Enemy
					if(name == L"ObjectID" || name == L"IDEnemy")
					{

						objectName = g->guienv->addStaticText(L"", rect<s32>(x + propWidth/2 + 20, y, x + propWidth - 40, y + 20), 
							false, false, parent, 1);

					}
				}

				

				height += 20;
			}
			break;

		case EAT_FLOAT: 
			g->guienv->addStaticText(label.c_str(), rect<s32>(x, y, x + 100, y + 20), 
				false, false, parent, 1);
			edit = g->guienv->addEditBox(L"", rect<s32>(x + 100, y, x + propWidth, y + 20), true,
				parent, 1);
			height = 20;
			break;

		case EAT_STRING:
			if (name.find(L"$") != -1)
			{
				if( name[0] == L'$' )
				{
					g->guienv->addStaticText(label.c_str(), rect<s32>(x, y, x + 100, y + 20), 
						false, false, parent, 1);
				}
				else
				{
					int pos = name.find(L"$");
					label = name.subString(0, pos);
					g->guienv->addStaticText(label.c_str(), rect<s32>(x, y, x + 100, y + 20), 
						false, false, parent, 1);
				}
			}
			else
			{
				g->guienv->addStaticText(label.c_str(), rect<s32>(x, y, x + 100, y + 20), 
					false, false, parent, 1);
			}

			if (name.find(L"$") != -1)
			{
				 edit = g->guienv->addComboBox(rect<s32>(x, y + 15, x + propWidth, y + 35), parent, 1);
				((IGUIComboBox*)edit)->addItem(L""); 
				
				if (name == "$Anim")
				{
					//special case 
					//see if object id is selected and get the list of animations if any 
					//Todo update this edit box .... but after property creation 
				}
				else
				{
					irr::s32 pos = name.find(L"$");				
					array<stringw> listArray = editor->getGameListArray(name.subString(pos+1, name.size() - 1));

					for (u32 z = 0; z < listArray.size(); z ++)
						((IGUIComboBox*)edit)->addItem(listArray[z].c_str());
				}
			}
			else
			{
				edit = g->guienv->addEditBox(L"", rect<s32>(x, y + 15, x + propWidth, y + 35), 
					true, parent, 1);
			}

			height = 35;
			break;

		case EAT_BOOL:
			g->guienv->addStaticText(label.c_str(), rect<s32>(x, y, x + 100, y + 20), 
				false, false, parent, 1);
			edit = g->guienv->addCheckBox(false, rect<s32>(x + propWidth - 20, y, x + propWidth, y + 20), 
				parent, 1);
			height = 20;
			break;

		case EAT_VECTOR3D: 
			g->guienv->addStaticText(label.c_str(), rect<s32>(x, y, x + 100, y + 20),
				false, false, parent, 1);
			edit = g->guienv->addEditBox(L"", rect<s32>(x, y + 15, x + propWidth, y + 35),
				true, parent, 1);
			height = 35;
			break;

		case EAT_COLOR: 
			g->guienv->addStaticText(label.c_str(), rect<s32>(x, y, x + 100, y + 20),
				false, false, parent, 1);
			edit = g->guienv->addEditBox(L"", rect<s32>(x, y + 15, x + propWidth, y + 35),
				true, parent, 1);
			height = 35;
			break;

		case EAT_COLORF: 
			g->guienv->addStaticText(label.c_str(), rect<s32>(x, y, x + 100, y + 20), false, false, 
				parent, 1);
			edit = g->guienv->addEditBox(L"", rect<s32>(x, y + 15, x + propWidth, y + 35), true,
				parent, 1);
			height = 35;
			break;

		case EAT_QUATERNION:
			g->guienv->addStaticText(label.c_str(), rect<s32>(x, y, x + 100, y + 20),
				false, false, parent, 1);
			edit = g->guienv->addEditBox(L"", rect<s32>(x, y + 15, x + propWidth, y + 35),
				true, parent, 1);
			height = 35;
			break;
	}
	
	CProperty prop;

	prop.m_GUIElementEdit = edit;
	prop.m_GUIElementButton = button;
	prop.m_Name = name;
	prop.m_Type = (E_ATTRIBUTE_TYPE)type;
	prop.m_bUserData = false;

	if(name == L"ObjectID" || name == L"IDEnemy")
	{
		//editor->getSceneObjectFromID(
		prop.m_GUIElementObjectName = objectName;
	}

	m_CinematicProperties.push_back(prop);
	//if just create property $Anim update it's list box

	if (cmd->m_Name == "SetAnim" && name == "$Anim")
	{
		if (m_CinematicThread && m_CinematicThread->m_Obj)
		{
			s32 objId = m_CinematicThread->m_Obj->m_SceneNode->getID();
			if (objId != -1)
			{
				UpdateAnimationList(objId);
			}
		}
		else
		{
			irr::s32 objectId = cmd->m_Attributes->getAttributeAsInt("ObjectID");
			if( objectId > 0 )
			{			
				UpdateAnimationList(objectId);
			}
		}
	}	

	height += 5;	//spacing
	return height;
}

bool CCinematicEditor::propertyButtonPressed(const SEvent& event)
{
	IGUIButton* button = (IGUIButton*)event.GUIEvent.Caller;
	CProperty* changedProp = 0;
	stringw caption;

	for (u32 i = 0, isize = m_CinematicProperties.size(); i<isize; i ++)	
	{
		if (m_CinematicProperties[i].m_GUIElementButton == button)
		{
			changedProp = &m_CinematicProperties[i];
			break;
		}
	}

	if (changedProp)
	{
		caption = stringw(L"Open ") + changedProp->m_Name;
		g->device->getFileSystem()->changeWorkingDirectoryTo(ui->m_UserBrowsePath.c_str());
		g->guienv->addFileOpenDialog(caption.c_str(), true, 0, FILE_PROP_FILE_OPEN_DIALOG);
		ui->m_FileOpenProp = changedProp;
		return true;
	}

	return false;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CCinematicEditor::createCommandProperties()
{
	m_CinematicProperties.clear();
	
	if (m_PropTab)
		m_PropTab->remove();

	m_PropTab = 0;

	if (m_CurrentCinematicIndex < 0 || !m_CurrentCinematic || m_CurrentCinematicIndex >= (int)(*m_CurrentCinematic).size())
		return;

	rect<s32> r1 = m_CinematicWindow->getRelativePosition();
	m_PropTab = g->guienv->addTab(rect<s32>( r1.getWidth() / 2 - 10, r1.getHeight() / 2 + 60, r1.getWidth() - 20, r1.getHeight() / 2 + 350), m_CinematicWindow);
	//m_PropTab->setDrawBackground(true);
	//m_PropTab->setBackgroundColor(SColor( 255 , 0 , 255, 0 ));

	const c8* attName;
	int y = 0;		


	for (u32 i = 0; i < (*m_CurrentCinematic)[m_CurrentCinematicIndex]->m_Attributes->getAttributeCount(); i ++)
	{
		attName = (*m_CurrentCinematic)[m_CurrentCinematicIndex]->m_Attributes->getAttributeName(i);
		y += createProperty(attName, 
			(*m_CurrentCinematic)[m_CurrentCinematicIndex]->m_Attributes->getAttributeType(i), 
			0, y, m_PropTab , (*m_CurrentCinematic)[m_CurrentCinematicIndex]);
	}

	updateProperties();
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CCinematicEditor::updateProperties()
{
	IAttributes* attr = (*m_CurrentCinematic)[m_CurrentCinematicIndex]->m_Attributes;
	stringw valueStr;
	
	for (u32 i = 0; i < m_CinematicProperties.size(); i ++)
	{		
		valueStr = "";
		stringw tmpStrW = m_CinematicProperties[i].m_Name;
		stringc tmpStrC = stringc(tmpStrW.c_str());
		const c8* propName = tmpStrC.c_str();
		IGUIElement* edit = m_CinematicProperties[i].m_GUIElementEdit;
		int value;
		switch (m_CinematicProperties[i].m_Type)
		{
			case EAT_INT:
				
				value = attr->getAttributeAsInt(propName);
				valueStr = stringw(value);

				if (tmpStrW.c_str()[0] == L'^')		
				{
					int val = ui->stringToInt(valueStr);

					if (val < 0)				
						((IGUIComboBox*)edit)->setSelected(0);
					else
					{
						stringw filter = FindStringBetween(tmpStrW, L'^', 1);	
	
						int index = 0;

						for (u32 z = 0; z < editor->m_SceneObjects.size(); z ++)
						{
							if (filter == L"" || filter == editor->m_SceneObjects[z]->m_UserData->getAttributeAsStringW("!GameType"))
							{
								if (editor->m_SceneObjects[z]->m_SceneNode->getID() == ui->stringToInt(valueStr))					
								{
									((IGUIComboBox*)edit)->setSelected(index + 1);
									break;
								}

								index++;
							}
						}
					}
				}
				else if ( tmpStrW.c_str()[0] == L'$' )
				{
					//array<stringw> listArray = editor->getGameListArray(tmpStrW.subString(1, tmpStrW.size() - 1));
					//for (u32 z = 0; z < listArray.size(); z ++)
					//	if (z == value)
					//	{
							((IGUIComboBox*)edit)->setSelected(value);
					//	}
				}
				break;

			case EAT_BOOL:
				if (m_CinematicProperties[i].m_GUIElementEdit)
				{
					((IGUICheckBox*)m_CinematicProperties[i].m_GUIElementEdit)->setChecked(attr->getAttributeAsBool(propName));
				}
				break;					
			
			case EAT_FLOAT: 
				valueStr = stringw(attr->getAttributeAsFloat(propName));
				break;				
			
			case EAT_VECTOR3D:
				{
					vector3df vec = attr->getAttributeAsVector3d(propName);
					valueStr = ui->vector3DToString(&vec, 5);
				}
				break;

			case EAT_COLOR:
				{
					SColor color = attr->getAttributeAsColor(propName);
					valueStr = ui->colorToString(&color);
				}
				break;

			case EAT_STRING: 
				valueStr = attr->getAttributeAsStringW(propName);

				if (tmpStrW.find( L"$") != -1)
				{
					if (tmpStrW == "$Anim")
					{
						//special case 
						for (u32 z = 0; z < animationList.size(); z ++)
							if (animationList[z] == valueStr)
							{
								((IGUIComboBox*)edit)->setSelected(z);
							}
					}
					else
					{
						irr::s32 pos = tmpStrW.find(L"$");
						array<stringw> listArray = editor->getGameListArray(tmpStrW.subString(pos+1, tmpStrW.size() - 1));
						for (u32 z = 0; z < listArray.size(); z ++)
							if (listArray[z] == valueStr)
							{
								((IGUIComboBox*)edit)->setSelected(z + 1);
							}
					}
				}
				break;

			case EAT_QUATERNION:
				//if (m_CinematicProperties[i].m_Name == L"Rotation")
				{
					vector3df vec;
					attr->getAttributeAsQuaternion(propName).toEuler(vec);
					vec *= vector3df(180.0f/PI, 180.0f/PI, 180.0f/PI);				
					valueStr = ui->vector3DToString(&vec, 5);
				}
				break;
		}	

		if (m_CinematicProperties[i].m_GUIElementEdit)
		{
			m_CinematicProperties[i].m_GUIElementEdit->setText(valueStr.c_str());
		}

		// set the ObjectID and IDEnemy name for display
		if (m_CinematicProperties[i].m_Name == L"ObjectID" || m_CinematicProperties[i].m_Name == L"IDEnemy")
		{
			if(m_CinematicProperties[i].m_GUIElementObjectName)
			{
				//CSceneObject* sceneObject = editor->getSceneObjectFromID(value);
				 irr::gui::TreeNode* treeNode = ui->m_sceneGraphTree->FindNode(value);
				 if(treeNode)
				 {
					 m_CinematicProperties[i].m_GUIElementObjectName->setText(treeNode->Text.c_str());
				 }
			}
		}
	}
}

void CCinematicEditor::UpdatePropOfChangeCamera(CCinematicCommand* cmd)
{	
	bool setFromObj = false;

	int col = m_cinematicCtrl->GetSelectedColumn();
	if( col == 1 )
	{
		setFromObj = true;		
	}
	else
	{
		irr::core::stringw CmdName = "ChangeCamera";
		bool bFound = false;
		int column = col -1;
		for(; column >= 1 ;column-- )
		{
			void* data = m_cinematicCtrl->GetTableData( m_cinematicCtrl->GetSelectedRow(),column );
			if( data!= NULL )
			{
				array<CCinematicCommand*> * cmds = static_cast< array<CCinematicCommand*> *>(data);
				if( ((*cmds).size() >0) && (*cmds)[0]->m_Name == CmdName )
				{
					bFound = true;
					break;
				}
			}
		}
		if( bFound )
		{
			void* data = m_cinematicCtrl->GetTableData( m_cinematicCtrl->GetSelectedRow(),column );
			array<CCinematicCommand*> * cmds = static_cast< array<CCinematicCommand*> *>(data);
			if( (*cmds)[0]->m_Name == CmdName )
			{
				irr::core::vector3df pos = (*cmds)[0]->m_Attributes->getAttributeAsVector3d("target");
				cmd->m_Attributes->setAttribute("target",pos);

				irr::core::vector3df dir = (*cmds)[0]->m_Attributes->getAttributeAsVector3d("dir");
				cmd->m_Attributes->setAttribute("dir",dir);

				irr::f32 dist = (*cmds)[0]->m_Attributes->getAttributeAsFloat("Distance");
				cmd->m_Attributes->setAttribute("Distance",dist);				
			}
		}
		else
		{
			setFromObj = true;
		}
	}	

	if(setFromObj)
	{
		irr::core::vector3df targetPos = m_Target->m_SceneNode->getAbsolutePosition();//get target pos from cinematic obj
		cmd->m_Attributes->setAttribute("target",targetPos);		

		//set default dir and distance		
		cmd->m_Attributes->setAttribute("dir",irr::core::vector3df(0,1,0));		
		cmd->m_Attributes->setAttribute("Distance",800);		
	}

	UpdateCurrentCinematic();
}

void CCinematicEditor::UpdatePropOfMoveObject(CCinematicCommand* cmd, int col)
{
	bool setFromObj = false;

	if( col == 1 )
	{
		setFromObj = true;		
	}
	else
	{		
		CCinematicCommand* preCmd = 0;

		int column = col -1;
		irr::core::stringw CmdName = "MoveObject";
		for(; column >= 1 ;column-- )
		{			
			void* data = m_cinematicCtrl->GetTableData( m_cinematicCtrl->GetSelectedRow(),column );
			if( data!= NULL )
			{
				array<CCinematicCommand*> * cmds = static_cast< array<CCinematicCommand*> *>(data);
				for(int c=0; c<cmds->size(); ++c)
				{
					if( ((*cmds).size() >0) && (*cmds)[c]->m_Name == CmdName )
					{
						preCmd = (*cmds)[c];
						break;
					}
				}
			}
		}
		if( preCmd )
		{			
			irr::core::vector3df pos = preCmd->m_Attributes->getAttributeAsVector3d("pos");
			cmd->m_Attributes->setAttribute("pos",pos);

			irr::core::quaternion rot = preCmd->m_Attributes->getAttributeAsQuaternion("rot");
			cmd->m_Attributes->setAttribute("rot",rot);

			cmd->m_Attributes->setAttribute("abspos",m_CinematicThread->m_Obj->m_SceneNode->getAbsolutePosition());							
		}
		else
		{
			setFromObj = true;							
		}
	}

	if(setFromObj)
	{
		irr::core::vector3df pos = m_CinematicThread->m_Obj->m_SceneNode->getPosition();
		cmd->m_Attributes->setAttribute("pos",pos);

		irr::core::quaternion rot =  m_CinematicThread->m_Obj->m_SceneNode->getRotation();		
		cmd->m_Attributes->setAttribute("rot",rot);

		cmd->m_Attributes->setAttribute("abspos",m_CinematicThread->m_Obj->m_SceneNode->getAbsolutePosition());			
	}

	UpdateCurrentCinematic();
}

//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
bool CCinematicEditor::propertyEditBoxEnter(const SEvent& event)
{
	IGUIEditBox* editBox = (IGUIEditBox*)event.GUIEvent.Caller;

	CProperty* changedProp = 0;

	for (u32 i = 0; i < m_CinematicProperties.size(); i ++)	
		if (m_CinematicProperties[i].m_GUIElementEdit == editBox)
		{
			changedProp = &m_CinematicProperties[i];
			break;
		}
	
	if (changedProp)
	{
		if (changedProp->m_Type == EAT_QUATERNION)
		{
			vector3df vec = ui->stringToVector3D(editBox->getText());
			vec *= vector3df(PI/180.0f, PI/180.0f, PI/180.0f);
			(*m_CurrentCinematic)[m_CurrentCinematicIndex]->m_Attributes->setAttribute(stringc(changedProp->m_Name.c_str()).c_str(), quaternion(vec));
		}
		else if (changedProp->m_Type == EAT_COLOR)
		{
			SColor color = ui->stringToColor(editBox->getText());
			(*m_CurrentCinematic)[m_CurrentCinematicIndex]->m_Attributes->setAttribute(stringc(changedProp->m_Name.c_str()).c_str(), color);
		}
		else
		{
			(*m_CurrentCinematic)[m_CurrentCinematicIndex]->m_Attributes->setAttribute(stringc(changedProp->m_Name.c_str()).c_str(), editBox->getText());
			
			//if command is set anim and object id is != -1 
			// fill combobox's animation list ...
			CCinematicCommand* cmd = (*m_CurrentCinematic)[m_CurrentCinematicIndex];
			if (cmd->m_Name == L"SetAnim" && changedProp->m_Name == L"ObjectID")
			{
				s32 objId = cmd->m_Attributes->getAttributeAsInt(stringc(changedProp->m_Name.c_str()).c_str());
				if (objId != -1)
				{
					UpdateAnimationList(objId);
				}
			}
		}

		updateTimeLine();

		return true;
	}

	return false;	
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CCinematicEditor::updateCurrentCinematicList()
{
	stringw name;

	if (m_KeyFrameList)
	{
		m_KeyFrameList->clear();

		if (m_CurrentCinematic)
		{
			for (u32 i = 0; i < (*m_CurrentCinematic).size(); i ++)
			{
				name = stringw(i) + stringw(": ") + (*m_CurrentCinematic)[i]->m_Name;	
				m_KeyFrameList->addItem(name.c_str());
			}

			if (m_CurrentCinematicIndex > -1)
				m_KeyFrameList->setSelected(m_CurrentCinematicIndex);
		}
	}
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CCinematicEditor::setObjectID(s32 id)
{
	if (m_Active && m_CurrentCinematicIndex > -1 && m_CurrentCinematic && (*m_CurrentCinematic).size() > 0)
	{
		if ((*m_CurrentCinematic)[m_CurrentCinematicIndex]->m_Attributes->findAttribute("ObjectID") > -1)
		{
			(*m_CurrentCinematic)[m_CurrentCinematicIndex]->m_Attributes->setAttribute("ObjectID", id);
		}

		if ((*m_CurrentCinematic)[m_CurrentCinematicIndex]->m_Attributes->findAttribute("IDEnemy") > -1)
		{
			(*m_CurrentCinematic)[m_CurrentCinematicIndex]->m_Attributes->setAttribute("IDEnemy", id);
		}

			if ((*m_CurrentCinematic)[m_CurrentCinematicIndex]->m_Attributes->findAttribute("CinematicID") > -1)
		{
			(*m_CurrentCinematic)[m_CurrentCinematicIndex]->m_Attributes->setAttribute("CinematicID", id);
		}

		// fill combobox's animation list ...
		CCinematicCommand* cmd = (*m_CurrentCinematic)[m_CurrentCinematicIndex];
		if (cmd->m_Name == L"SetAnim" )
		{
			s32 objId = cmd->m_Attributes->getAttributeAsInt("ObjectID");
			UpdateAnimationList(objId);	
		}

		updateProperties();		
	}		
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CCinematicEditor::setObjectProperties()
{
	if (m_Active && m_CurrentCinematicIndex > -1 && m_CurrentCinematic)
	{
		if ((*m_CurrentCinematic).size() > 0 )
		{
			IAttributes* attr = (*m_CurrentCinematic)[m_CurrentCinematicIndex]->m_Attributes;
			for (u32 i = 0; i < attr->getAttributeCount(); i ++)
			{
				stringc name = attr->getAttributeName(i);
				if (name == "Position")
					attr->setAttribute(name.c_str(), editor->getSelectedNode()->getPosition());
				if (name == "Rotation")
					attr->setAttribute(name.c_str(), editor->getSelectedNode()->getRotation());
				if (name == "Scale")
					attr->setAttribute(name.c_str(), editor->getSelectedNode()->getScale());
			}

			updateProperties();
		}
	}
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CCinematicEditor::executeCinematicToSelection()
{
	if (m_CurrentCinematicIndex < 0 || !m_CurrentCinematic)
		return;

	//restore original object params
	for (u32 i = 0; i < m_SavedObjectParameters.size(); i ++)
	{
		editor->m_SceneObjects[i]->m_SceneNode->setPosition(m_SavedObjectParameters[i].pos);
		core::vector3df rotate;
		m_SavedObjectParameters[i].rot.toEuler(rotate);
		editor->m_SceneObjects[i]->m_SceneNode->setRotation(rotate);
		editor->m_SceneObjects[i]->m_SceneNode->setScale(m_SavedObjectParameters[i].scale);
	}	
	
	IAttributes* attr;	
	stringc name;
	s32 objectID = -1;

	//applay cinematic transformations
	for (u32 i = 0; i < (u32)m_CurrentCinematicIndex + 1; i ++)
	{
		attr = (*m_CurrentCinematic)[i]->m_Attributes;
		objectID = -1;

		for (u32 j = 0; j < attr->getAttributeCount(); j ++)
		{
			name = attr->getAttributeName(j);			
			if (name == "ObjectID")
			{
				objectID = attr->getAttributeAsInt(j);
				break;
			}
		}
		
		if (objectID > -1)
		{
			CSceneObject* sceneObject = editor->getSceneObjectFromID(objectID);
			if (sceneObject)
			{
				for (u32 j = 0; j < attr->getAttributeCount(); j ++)
				{			
					name = attr->getAttributeName(j);

					if (name == "Position")
						sceneObject->m_SceneNode->setPosition(attr->getAttributeAsVector3d(j));

					if (name == "Rotation")
					{
						core::vector3df rotate;
						attr->getAttributeAsQuaternion(j).toEuler(rotate);
						sceneObject->m_SceneNode->setRotation(rotate);
					}

					if (name == "Scale")
						sceneObject->m_SceneNode->setScale(attr->getAttributeAsVector3d(j));
				}
			}
		}			

	}

	//select current object
	if (objectID > -1)
	{
		CSceneObject* obj = editor->getSceneObjectFromID(objectID);
		if (obj)
		{
			editor->setSelectedNode(0);
			editor->setSelectedNode(obj->m_SceneNode);
		}
	}
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CCinematicEditor::writeCinematicCommands(IWriteFile* f)
{
	for (u32 i = 0; i <  m_CinematicCommands.size(); i ++)
	{
		if (m_CinematicCommands[i])
		{
			stringc line = "#define ";
			stringc name = "CMD_";
			name.append(stringc(m_CinematicCommands[i]->m_Name.c_str()));
			
			name.make_upper();
			line.append(name);			
			line.append("\t\t\t") ;
			line += m_CinematicCommands[i]->m_id;
			line.append("\n");
			f->write(line.c_str() , line.size());
		}
	}
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
s32 CCinematicEditor::FindId(stringw name)
{
	for (u32 i = 0; i <  m_CinematicCommands.size(); i ++)
	{
		if (m_CinematicCommands[i])
		{
			if (m_CinematicCommands[i]->m_Name == name)
			{
				return m_CinematicCommands[i]->m_id;
			}
		}
	}

	return -1;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
CCinematicCommand* CCinematicEditor::FindCinematic(stringw name)
{
	for (u32 i = 0; i <  m_CinematicCommands.size(); i ++)
	{
		if (m_CinematicCommands[i])
		{
			if (m_CinematicCommands[i]->m_Name == name)
			{
				return m_CinematicCommands[i];
			}
		}
	}

	return 0;
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CCinematicEditor::UpdateAnimationList(s32 objId)
{
	if (objId != -1)
	{
		CSceneObject* obj = editor->getSceneObjectFromID(objId);
		
		if (obj)
		{
			animationList = obj->GetAnimationNames();
			//search for property
			CProperty* changedProp = 0;

			for (u32 i = 0; i < m_CinematicProperties.size(); i ++)	
			{
				if (m_CinematicProperties[i].m_Name == "$Anim")
				{
					changedProp = &m_CinematicProperties[i];
					break;
				}
			}

			if (changedProp)
			{
				((IGUIComboBox*)changedProp->m_GUIElementEdit)->clear();
				for (u32 z = 0; z < animationList.size(); z ++)
					((IGUIComboBox*)changedProp->m_GUIElementEdit)->addItem(animationList[z].c_str());
			}
		}
	}
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CCinematicEditor::updateTimeLine()
{
	  if (m_oldSelectedRow != -1)
	  {
			for (int i = m_oldSelectedCol; i < m_oldSelectedCol + m_oldSelectedCount; i++)
			{
				stringw str = m_cinematicCtrl->GetTableText(m_oldSelectedRow, i);
				if (str == L"+")
				{
				  m_cinematicCtrl->SetTableColor(m_oldSelectedRow,
					  i, SColor(255,255,0,0), L"", 1);
				}
			}

			m_oldSelectedRow = -1;
			m_oldSelectedCol = -1;
			m_oldSelectedCount = -1;
	  }

	  s32 maxTime = 0;

	  if (m_CinematicThread && m_CinematicThread->m_Obj && m_CurrentCinematic)
	  {
		  for (int i=0; i < m_CurrentCinematic->size(); i++)
		  {
			  (*m_CurrentCinematic)[i]->CalculateTime(m_CinematicThread);

			  if (maxTime < (*m_CurrentCinematic)[i]->m_time)
			  {
				  maxTime = (*m_CurrentCinematic)[i]->m_time;
			  }
		  }

		
		  m_oldSelectedRow = m_cinematicCtrl->GetSelectedRow();
		  m_oldSelectedCol = m_cinematicCtrl->GetSelectedColumn();
		  m_oldSelectedCount = maxTime / EVENTS_INTERVAL;

			for (int i = m_oldSelectedCol; i < m_oldSelectedCol + m_oldSelectedCount; i++)
			{
				stringw str = m_cinematicCtrl->GetTableText(m_oldSelectedRow, i);
				if (str != L"X")
				{
				  m_cinematicCtrl->SetTableColor(m_oldSelectedRow,
					  i, SColor(255,255,0,0), L"+", 1);
				}
			}
	  }
}
//--------------------------------------------------------------------------------------------------
//
//--------------------------------------------------------------------------------------------------
void CCinematicEditor::UpdateCurrentCinematic()
{	
	 void* cdata = m_cinematicCtrl->GetTableData( m_cinematicCtrl->GetSelectedRow() , m_cinematicCtrl->GetSelectedColumn() );
	 
	  if (m_cinematicCtrl->GetSelectedColumn() != 0)
	  {		 
		 array<CCinematicCommand*> * cmds = static_cast< array<CCinematicCommand*> *>(cdata);		 
		 m_CurrentCinematic = cmds;		  
	  }

	m_CurrentCinematicIndex = 0;
	createCommandProperties();
	updateCurrentCinematicList();
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
void CCinematicEditor::enableKFButtons(bool b)
{
	IGUIElement* e = m_CinematicWindow->getElementFromId(CINEMATIC_ID_UP_BTN , true);
	e->setEnabled(b);
	e = m_CinematicWindow->getElementFromId(CINEMATIC_ID_DOWN_BTN , true);
	e->setEnabled(b);
	e = m_CinematicWindow->getElementFromId(CINEMATIC_ID_DELETE_BTN , true);
	e->setEnabled(b);
	e = m_CinematicWindow->getElementFromId(CINEMATIC_ID_CLONE_BTN , true);
	e->setEnabled(b);
	e = m_CinematicWindow->getElementFromId(CINEMATIC_ID_ADD_BTN , true );
	e->setEnabled(b);
	e = m_CinematicWindow->getElementFromId(CINEMATIC_ID_COMMAND_COMBO , true);
	e->setEnabled(b);

	//link button will be enabled only when a thread is selected 
	e = m_CinematicWindow->getElementFromId(CINEMATIC_ID_LINK_BTN , true);
	e->setEnabled(!b);

	e = m_CinematicWindow->getElementFromId(CINEMATIC_ID_CHANGE_BTN , true);
	e->setEnabled(b);	
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
void  CCinematicEditor::SetThreadObject(irr::s32 objId)
{
	IGUIElement* e = m_CinematicWindow->getElementFromId(CINEMATIC_ID_LINK_BTN , true);
	IGUIButton* b = (IGUIButton*)e;
	if (b->isPressed())
	{
		//set 
		b->setPressed(false);
	}
	
	int row = m_cinematicCtrl->GetSelectedRow();
	int col = m_cinematicCtrl->GetSelectedColumn();
	if(col!= 0)
	{
		return;
	}

	void * data = m_cinematicCtrl->GetSelectedData();

	CCinematicThread* thread = static_cast<CCinematicThread*>(data);							

	if (thread && 
		thread->m_Type == E_THREAD_TYPE_OBJ)
	{																		
		for (u32 i = 0; i < editor->m_SceneObjects.size(); i ++)
		{
			CSceneObject* obj = editor->m_SceneObjects[i];
			if (obj && obj->m_SceneNode->getID() == objId)
			{							
				thread->m_Obj = obj;
				
				stringw str = L"";
				str	+= objId;

				m_ObjectsBox->setText(str.c_str());

				break;
			}	
		}						
	 }	
}

void CCinematicEditor::AutoSetThreadObj(CCinematicThread* thread, int objType)
{	
	for (u32 i = 0; i < editor->m_SceneObjects.size(); i ++)
	{
		CSceneObject* obj = editor->m_SceneObjects[i];
		if (obj && obj->m_type==objType)
		{	
			thread->m_Obj = obj;
			break;
		}	
	}
}

void CCinematicEditor::AutoSetPlayerThreadObj(CCinematicThread* thread)
{
	assert(thread->m_Type==E_THREAD_TYPE_PLAYER);

	AutoSetThreadObj(thread,E_OBJ_SPIDER_MAN);
}

void CCinematicEditor::SetVisible( bool b )
{
	if( m_CinematicWindow )
	{
		m_CinematicWindow->setVisible( b );
	}
}

///////////////// for preview ///////////////////////////////////////////////////////////

bool CCinematicEditor::InitPreviewData()
{
	m_objThreads.clear();
	m_cameraThread = 0;
	editor->m_cnm_objUpdateList.clear();

	if (m_cinematicCtrl)
	{
		int rows = m_cinematicCtrl->GetTableRows();
		int columns = m_cinematicCtrl->GetTableColumns();

		CCinematicThread* thread = 0;

		for (u32 i = 0 ; i < rows ; i++ )
		{
			void * cdata = m_cinematicCtrl->GetTableData( i , 0 );
			thread = static_cast<CCinematicThread*>(cdata);
			thread->m_ThreadCinematics->clear();
			if (thread && 
				(thread->m_Type==E_THREAD_TYPE_CAMERA || 
				thread->m_Type==E_THREAD_TYPE_OBJ && thread->m_Obj!=0||
				thread->m_Type==E_THREAD_TYPE_PLAYER && thread->m_Obj!=0 )
				)
			{
				thread->m_lastExecdKeyFrame = -1;
				thread->m_lastExecdKeyFrame2 = -1;
				thread->m_lastExecdCmd = -1;
				if(thread->m_Obj!=0)
					thread->m_visibleInScene = thread->m_Obj->m_SceneNode->isVisible();

				for (u32 j = 1 ; j < columns ; j++ )
				{
					void * data = m_cinematicCtrl->GetTableData( i , j );
					array<CCinematicCommand*>* commands = static_cast<array<CCinematicCommand*>*>(data);
					if (commands && (*commands).size() > 0)
					{
						if(thread->m_Type==E_THREAD_TYPE_CAMERA)
						{
							CCinematicCommand* cmd = (*commands)[0]; //camera thread only use one command
							cmd->m_time = (j-1)*EVENTS_INTERVAL;
							thread->m_ThreadCinematics->push_back(cmd);																		
						}
						else
						{
							for (u32 k = 0 ; k < (*commands).size(); k++)
							{
								CCinematicCommand* cmd = (*commands)[k];
								cmd->m_time = (j-1)*EVENTS_INTERVAL;
								thread->m_ThreadCinematics->push_back(cmd);	
							}	
						}
					}
				}

				if(thread->m_ThreadCinematics->size()>0)
				{
					if(thread->m_Type==E_THREAD_TYPE_CAMERA)
						m_cameraThread = thread;
					else
					{
						m_objThreads.push_back(thread);	
						if(thread->m_Obj!=0)
							editor->m_cnm_objUpdateList.push_back(thread->m_Obj);						
					}
				}
			}						
		}
	}

	return (m_cameraThread!=0 || m_objThreads.size()>0);			
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void CCinematicEditor::MoveRangeCmds(bool doMove)
{
	bool valid = false;
	int rows,columns;
	if (m_cinematicCtrl)
	{
		rows = m_cinematicCtrl->GetTableRows();
		columns = m_cinematicCtrl->GetTableColumns();
		if(rows<=0 || columns<=0 || m_cinematicCtrl->GetSelectedRow()<0)
			valid = false;
		else
			valid = true;
	}

	if(!valid)
	{
		g->guienv->addMessageBox(L"Error!", L"The cinematic is empty or no thread is selected!", true);
		return;
	}

	int offset = m_moveRangeOffsetBox->getValue();
	if(offset==0)
	{
		g->guienv->addMessageBox(L"??", L"Offset is 0, no need to move!", true);
		return;
	}
	int from = m_moveRangeStartBox->getValue();
	int to = m_moveRangeEndBox->getValue();
	if(from>to)
		std::swap(from,to);

	int fromColumn = 1 + from/EVENTS_INTERVAL;
	int toColumn = 1 + to/EVENTS_INTERVAL;
	int startColumn = fromColumn;
	int endColumn = toColumn;
	
	if(doMove)
	{	
		int deltJ = 1;
		if(offset>0)
		{
			startColumn = toColumn;
			endColumn = fromColumn;
			deltJ = -1;		
		}

		//for (u32 i = 0 ; i < rows ; i++ )
		int i = m_cinematicCtrl->GetSelectedRow();
		{				
			for (u32 j = startColumn ; (offset>0)? j >= endColumn : j <= endColumn ; j+=deltJ )
			{
				void * data = m_cinematicCtrl->GetTableData( i , j );
				array<CCinematicCommand*>* srcCommands = static_cast<array<CCinematicCommand*>*>(data);
				if(srcCommands && (*srcCommands).size() > 0)
				{
					//cut cmds
					m_cinematicCtrl->SetTableData(  i , j  , NULL );
					m_cinematicCtrl->SetTableColor( i , j , SColor(255,0,0,0) , L"") ;

					//past cmds to dest				
					int destCol = j+offset;
					if(destCol>=1 && destCol<=MAX_COLUMNS+1)
					{
						void * ddata = m_cinematicCtrl->GetTableData( i , destCol );
						array<CCinematicCommand*>* destCommands = static_cast<array<CCinematicCommand*>*>(ddata);
						if (destCommands == 0)
						{
							//create commands here 
							destCommands = new array<CCinematicCommand*>;	
							m_cinematicCtrl->SetTableData(i , destCol, (void*) destCommands );
						}

						//get commands from 
						for (int cmd = 0 ; cmd < srcCommands->size() ; cmd ++)
						{
							CCinematicCommand* newCmd = new CCinematicCommand(*(*srcCommands)[cmd]);
							destCommands->push_back(  newCmd );
						}

						m_cinematicCtrl->SetTableColor(i , destCol,  SColor(255,0,0,0) , L"X") ;						
					}
				}				
			}
		}
	}
	else
	{					
		wchar_t buf[256];
		wsprintf(buf,L"Will move all commands in range [ %d Ms ~  %d Ms ] with offset %d columns.\n",from,to,offset);
		stringw msg(buf);
		
		int startDest = startColumn+offset;
		int endDest = endColumn+offset;

		if(startDest<=0 || endDest>MAX_COLUMNS+1)
		{
			msg+=L"\nWarning!!! The dest columns range is out of range [1,";
			msg+=MAX_COLUMNS;
			msg+=L"], the commands out of range will be deleted!\n";
		}

		msg+=L"\nAre you sure?";

		g->guienv->addMessageBox(L"Confirm!",msg.c_str(), true, EMBF_YES | EMBF_NO, 0, MSG_BOX_CONFIRM_MOVE_RANGE );
	}
}


void CCinematicEditor::JumpToKeyFrame(JUMP_KF_ACTION jumpAction)
{	
	bool valid = true;
	int rows,columns;
	if (m_cinematicCtrl)
	{
		rows = m_cinematicCtrl->GetTableRows();
		columns = m_cinematicCtrl->GetTableColumns();
		if(rows<=0 || columns<=0 || m_cinematicCtrl->GetSelectedRow()<0)
		{
			valid = false;
		}

		if((jumpAction==KF_PREV || jumpAction==KF_NEXT) && m_cinematicCtrl->GetSelectedColumn()<0)
		{
			valid = false;
		}
	}

	if(!valid)
	{
		//g->guienv->addMessageBox(L"Error!", L"The cinematic is empty or no thread / key frame is selected!", true);
		return;
	}
	

	s32 startColumn, endColumn;
	int deltJ;

	if(jumpAction==KF_FIRST)
	{
		startColumn = 1;
		endColumn = columns-1;
		deltJ = 1;	
	}
	else if(jumpAction==KF_LAST)
	{
		startColumn = columns-1;
		endColumn = 1;
		deltJ = -1;
	}
	else if(jumpAction==KF_NEXT)
	{
		startColumn = m_cinematicCtrl->GetSelectedColumn()+1;
		if(startColumn>columns-1)
		{
			//g->guienv->addMessageBox(L"Info!", L"Already at last key frame", true);
			return;
		}
		endColumn = columns-1;
		deltJ = 1;
	}
	else
	{
		startColumn = m_cinematicCtrl->GetSelectedColumn()-1;
		if(startColumn<1)
		{
			//g->guienv->addMessageBox(L"Info!", L"Already at first key frame", true);
			return;
		}
		endColumn = 1;
		deltJ = -1;
	}

	int i = m_cinematicCtrl->GetSelectedRow();
	for (u32 j = startColumn ; (deltJ==-1)? j >= endColumn : j <= endColumn ; j+=deltJ )
	{
		void * data = m_cinematicCtrl->GetTableData( i , j );
		array<CCinematicCommand*>* srcCommands = static_cast<array<CCinematicCommand*>*>(data);
		if(srcCommands && (*srcCommands).size() > 0)
		{
			(static_cast<irr::gui::CGUICinematicCtrl*>(m_cinematicCtrl))->SetSelectedColumn(j);	
			return;
		}				
	}

}

int CCinematicEditor::GetNowTime()
{
	return (m_cinematicCtrl->GetSelectedColumn()-1)*EVENTS_INTERVAL;			
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////